package edu.cmu.cs.cs214.hw9.client.controllers.eventhandlers;

import java.awt.Container;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

import edu.cmu.cs.cs214.hw9.client.controllers.BackendCacheAdapter;
import edu.cmu.cs.cs214.hw9.client.controllers.FacelookController;
import edu.cmu.cs.cs214.hw9.client.controllers.SessionController;
import edu.cmu.cs.cs214.hw9.client.gui.FacelookScreen;
import edu.cmu.cs.cs214.hw9.client.gui.NewsFeedScreen;
import edu.cmu.cs.cs214.hw9.datatypes.Status;
import edu.cmu.cs.cs214.hw9.datatypes.User;

/**
 * Logs a user in.
 */
public class LoginHandler extends EventHandler {
	// Encapsulates the data required for the news feed screen, such as the 
	// most recent friend statuses and the user object for the newly logged in
	// user.
	private class LoginData {
		public List<Status> statusList;
		public User currentUser;
	}
	
	/**
	 * Log the user in using a separate thread, to prevent swing from freezing.
	 */
	private class LoginWorker extends SwingWorker<LoginData, Void> {
		private BackendCacheAdapter model;
		private Container contentPane;
		private String[] credentials;
		
		/**
		 * Constructs a new login request.
		 * 
		 * @param credentials Credentials provided by the user.
		 * 					  Credentials[0] = email.
		 * 					  Credentials[1] = password.
		 */
		public LoginWorker(String[] credentials) {
			this.credentials = credentials;
			model = controller.getModel();
			contentPane = controller.getFrame();
		}
		
		/**
		 * Logs the user in.
		 * 
		 * @return NULL if unsuccessful; associated login data otherwise.
		 */
		public LoginData doInBackground() {
			if (model.login(credentials[0], credentials[1])) {
				User currentUser = model.getUser(credentials[0]);
				
				LoginData data = new LoginData();
				data.currentUser = currentUser;
				data.statusList = model.getMostRecentFriendUpdates(currentUser, 10);
				
				return data;
			} else {
				return null;
			}
		}
		
		/**
		 * Spawns a new JFrame for the user if the login was successful. Notify the user
		 * if it wasn't.
		 */
		public void done() {
			try {
				LoginData data = get();
				if (data != null) {
					// Spawn new JFrame.
					JFrame frame = new JFrame("Facelook - Logged in as " + data.currentUser.getFullname());
					FacelookScreen newScreen = new NewsFeedScreen(data.statusList);
					
					// Spawn new controller to handle the logged in user.
					SessionController newController = new SessionController(model, frame, newScreen, data.currentUser);
					newScreen.registerController(newController);

					// Frame properties.
					frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
					frame.add(newScreen);
					frame.pack();
					frame.setResizable(false);
					
					frame.setVisible(true);
				} else {
					JOptionPane.showMessageDialog(contentPane,
							"There was an error logging in! Please check your email and password.",
							"Error logging in", JOptionPane.ERROR_MESSAGE);
				}
			} catch (Exception e) {
				throw new RuntimeException("Fatal error occured during login." + e.getMessage());
			}
		}
	};
	
	/**
	 * Set the current session controller to the provided controller.
	 * 
	 * @param controller Controller to associate with this event handler.
	 */
	public LoginHandler(FacelookController controller) { super(controller); }
	
	/**
	 * Create the login request and run it in an outside thread.
	 * 
	 * @param param Login data, as a string array. (of email and username)
	 */
	public void handleEvent(Object param) {
		LoginWorker loginWorker = new LoginWorker((String[]) param);
		loginWorker.execute();
	}
}
